/* 
 * Copyright (c) 2012 JSquirrelEngine
 * 
 * Permission is hereby granted, free of charge, to any person obtaining a copy of
 * this software and associated documentation files (the "Software"), to deal in 
 * the Software without restriction, including without limitation the rights to use,
 * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
 * Software, and to permit persons to whom the Software is furnished to do so, subject
 * to the following conditions:
 * 
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
 * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
 * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
 * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 * 
 */

package org.jsquirrel.rendering.LWJGLimpl;

import java.awt.Canvas;
import java.util.ArrayList;
import java.util.Iterator;

import org.jsquirrel.rendering.Camera;
import org.jsquirrel.rendering.Graphics;
import org.jsquirrel.rendering.Renderable;
import org.jsquirrel.rendering.RenderingContext;
import org.jsquirrel.rendering.RenderingContextListener;
import org.jsquirrel.rendering.RenderingException;
import org.lwjgl.LWJGLException;
import org.lwjgl.opengl.AWTGLCanvas;
import org.lwjgl.opengl.GL11;

public class LWJGL_RenderingContext extends RenderingContext {
	
	//*********************************************************************************************
	// INSTANCE ATTRIBUTES
	//*********************************************************************************************
	
	private ArrayList<Renderable> renderableObjects;
	
	private ArrayList<RenderingContextListener> contextListeners;
	
	private LWJGL_Graphics graphics;
	
	private AWTGLCanvas canvas;
	
	private LWJGL_Camera camera;
	
	private float[] clearColor;
	
	
	//*********************************************************************************************
	// CONSTRUCTORS
	//*********************************************************************************************
	
	public LWJGL_RenderingContext() throws RenderingException {
		
		renderableObjects = new ArrayList<Renderable>();
		contextListeners = new ArrayList<RenderingContextListener>();
		graphics = new LWJGL_Graphics();
		camera = new LWJGL_OrthoCamera();
		
		clearColor = new float[]{0, 0, 0, 0};
		
		try {
			canvas = new LWJGL_Canvas(this);
		} catch (LWJGLException e) {
			
			renderableObjects = null;
			graphics = null;
			canvas = null;
			camera = null;
			clearColor = null;
			
			throw new RenderingException("LWJGL_RenderingContext.LWJGL_RenderingContext(): error creating LWJGL_Canvas: " + e);
		}
	}
	
	//*********************************************************************************************
	// PUBLIC METHODS
	//*********************************************************************************************

	@Override
	public Canvas getCanvas() {
		
		return canvas;
	}

	@Override
	public Graphics getGraphics() {
		return graphics;
	}

	@Override
	public void addRenderableObject(Renderable r) {
		
		if(r != null) {
			renderableObjects.add(r);
		}
	}
	
	@Override
	public void addRenderingContextListener(RenderingContextListener listener) {
	
		if(listener != null) {
			contextListeners.add(listener);
		}
		
	}

	@Override
	public void clearRenderableObjects() {
		renderableObjects.clear();
		
	}
	
	@Override
	public void setCamera(Camera camera) {
		
		if(camera == null) {
			throw new NullPointerException("LWJGL_RenderingContext.setCamera(Camera): null camera");
		}
		
		if(!(camera instanceof LWJGL_Camera)) {
			throw new IllegalArgumentException("LWJGL_RenderingContext.setCamera(Camera): camera must be an instance of LWJGL_Camera");
		}
		
		this.camera = (LWJGL_Camera)camera;
	}
	
	@Override
	public void setClearColor(float red, float green, float blue, float alpha) {
		
		clearColor[0] = red;
		clearColor[1] = green;
		clearColor[2] = blue;
		clearColor[3] = alpha;
	}

	@Override
	public void update() {
		
		if(canvas != null) {
			canvas.repaint();
		}
	}

	@Override
	public void init() {
		
		System.out.println("LWJGL_RenderingContext.init()");
		
		// enables depth test
		GL11.glEnable(GL11.GL_DEPTH_TEST);
		
		// alpha blending
		GL11.glEnable(GL11.GL_BLEND);
		GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
		
		
		GL11.glClearColor(clearColor[0], clearColor[1], clearColor[2], clearColor[3]);
		GL11.glViewport(0, 0, canvas.getWidth(), canvas.getHeight());
		
		camera.prepare();
		
		// triggers context initialization
		Iterator<RenderingContextListener> it = contextListeners.iterator();
		while(it.hasNext()) {
			it.next().contextInitialized();
		}
	}
	
	public void render() {
		
		// buffer clearing
		GL11.glClearColor(clearColor[0], clearColor[1], clearColor[2], clearColor[3]);
		GL11.glClear(GL11.GL_COLOR_BUFFER_BIT | GL11.GL_DEPTH_BUFFER_BIT);
		
		// camera preparation
		camera.prepare();
		
		Iterator<Renderable> it = renderableObjects.iterator();
		while(it.hasNext()) {
			it.next().render(graphics);
		}
		
		// flush the buffers
		GL11.glFlush();
		
		try {
			canvas.swapBuffers();
		} catch (LWJGLException e) {
			
		}
	}

	

}
